package tech

import (
	"fmt"
	"slices"
	"ssp/set"
	"strings"
)

func (s *Solve) TurbotFish(g *Grid) (used bool, results []*Result) {
	all := g.findCandAllCells()
	for cand, bases := range all {
		if len(bases) < 4 {
			continue
		}
		for _, c0 := range bases {
			strongs1 := g.findCandStrongCells(cand, []*Cell{c0}, bases)
			for _, c1 := range strongs1 {
				weaks := g.findCandWeakCells([]*Cell{c0, c1}, bases)
				for _, c2 := range weaks {
					if c2.rowNum < c1.rowNum || c2.colNum < c1.colNum {
						continue
					}
					strongs2 := g.findCandStrongCells(cand, []*Cell{c0, c1, c2}, bases)
					for _, c3 := range strongs2 {
						if ok, rmCells := g.canRemoveSeenCandInPath(cand, []*Cell{c0, c3}, []*Cell{c0, c1, c2, c3}); ok {
							used = true
							result := new(Result)
							result.addRemoved(set.NewSet(cand), rmCells)
							result.setStrategyName(turbotFishName(c0, c1, c2, c3))
							result.addHelpChains(strTurbotFish(cand, []*Cell{c0, c1, c2, c3}))
							results = append(results, result)
						}
					}
				}
			}

		}
	}
	return
}

func (g *Grid) findCandStrongCells(cand int, links, bases []*Cell) (strongs []*Cell) {
	last := links[len(links)-1]
	for _, cell := range bases {
		if slices.Contains(links, cell) {
			continue
		}
		houses := g.getSameHouses([]*Cell{last, cell})
		if len(houses) == 0 {
			continue
		}
		if !isOnlyInHouses(cand, []*Cell{last, cell}, houses) {
			continue
		}
		strongs = append(strongs, cell)
	}
	return
}

func (g *Grid) findCandWeakCells(links, bases []*Cell) (weaks []*Cell) {
	last := links[len(links)-1]
	for _, cell := range bases {
		if slices.Contains(links, cell) {
			continue
		}
		houses := g.getSameHouses([]*Cell{last, cell})
		if len(houses) == 0 {
			continue
		}
		weaks = append(weaks, cell)
	}
	return
}

func strTurbotFish(cand int, cells []*Cell) string {
	var b strings.Builder
	fmt.Fprintf(&b, "R%vC%v[%v]=", cells[0].rowNum+1, cells[0].colNum+1, toValue(cand))
	fmt.Fprintf(&b, "R%vC%v[%v]-", cells[1].rowNum+1, cells[1].colNum+1, toValue(cand))
	fmt.Fprintf(&b, "R%vC%v[%v]=", cells[2].rowNum+1, cells[2].colNum+1, toValue(cand))
	fmt.Fprintf(&b, "R%vC%v[%v]", cells[3].rowNum+1, cells[3].colNum+1, toValue(cand))
	return b.String()
}

func isHouseType(a, b *Cell) int {
	if a.rowNum == b.rowNum {
		return 0
	} else if a.colNum == b.colNum {
		return 1
	} else {
		return 2
	}
}

func turbotFishName(c0, c1, c2, c3 *Cell) string {
	r1 := isHouseType(c0, c1)
	r2 := isHouseType(c2, c3)
	if (r1 == 0 && r2 == 0) || (r1 == 1 && r2 == 1) {
		return "Skyscraper"
	} else if (r1 == 0 && r2 == 1) || (r1 == 1 && r2 == 0) {
		return "Two-string kite"
	} else {
		return "Turbot Fish"
	}
}
